package co.msk8.client.visual.calculator.presenter;

import co.msk8.client.command.Action;
import co.msk8.client.command.Result;
import co.msk8.client.rpc.CalculatorServiceAsync;
import co.msk8.client.visual.calculator.view.CalculatorView;
import co.msk8.client.visual.calculator.view.CalculatorView.CalculatorPresenter;
import co.msk8.shared.Operation;
import co.msk8.shared.OperationContainer;
import co.msk8.shared.states.FirstDigitOperationState;
import co.msk8.shared.states.OperationState;
import co.msk8.shared.states.OperatorOperationState;
import co.msk8.shared.states.ResultOperationState;
import co.msk8.shared.states.SecondDigitOperationState;
import co.msk8.shared.states.VoidOperationState;

import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;

public class CalculatorPresenterImpl implements CalculatorPresenter<OperationContainer> {

	private OperationContainer operationContainer;
	private CalculatorView<OperationContainer> view;
	private CalculatorServiceAsync service;
	
	private OperationState currentState;
	private final OperationState voidState;
	private final OperationState firstDigitState;
	private final OperationState operatorState;
	private final OperationState secondDigitState;
	private final OperationState resultState;
	
	public CalculatorPresenterImpl(EventBus eventbus, CalculatorServiceAsync service, CalculatorView<OperationContainer> view) {
		
		this.view = view;
		
		this.view.setPresenter(this);
		
		this.service = service;
		
		this.voidState = new VoidOperationState(this);
		this.firstDigitState = new FirstDigitOperationState(this);
		this.operatorState = new OperatorOperationState(this);
		this.secondDigitState = new SecondDigitOperationState(this);
		this.resultState = new ResultOperationState(this);
		
		this.currentState = voidState;
	}

	public void setOperationContainer(OperationContainer container) {

		this.operationContainer = container;
		this.view.setOperationText(container.toString());
	}

	public OperationContainer getOperationContainer() {
		if (operationContainer == null) {
			operationContainer = new OperationContainer();
		}
		return this.operationContainer;
	}
	
	public OperationState getCurrentState() {
		return currentState;
	}

	public void setCurrentState(OperationState currentState) {
		this.currentState = currentState;
	}

	public OperationState getVoidState() {
		return voidState;
	}

	public OperationState getFirstDigitState() {
		return firstDigitState;
	}

	public OperationState getOperatorState() {
		return operatorState;
	}

	public OperationState getSecondDigitState() {
		return secondDigitState;
	}

	public OperationState getResultState() {
		return resultState;
	}
	
	public String getFirstOperator() {
		return getOperationContainer().getFirstOperator();
	}
	
	public void setFirstOperator(String digit) {
		
		getOperationContainer().setFirstOperator(digit);
	}
	
	public String getSecondOperator() {
		return getOperationContainer().getSecondOperator();
	}
	
	public void setSecondOperator(String digit) {
		getOperationContainer().setSecondOperator(digit);
	}
	
	public void setOperation(Operation operation) {
		getOperationContainer().setOperation(operation);
	}
	
	public void setResult(String result) {
		
		getOperationContainer().setResult(result);
	}
	
	public void go(final HasWidgets container) {
		
		container.clear();
	    container.add(view.asWidget());
	}
	
	//NEGOCIO
	
	public void initFirstOperator(int digit) {

		getOperationContainer().setOperation(null);
		getOperationContainer().setSecondOperator(null);
		getOperationContainer().setFirstOperator(getStringValue(digit));
		setCurrentState(getFirstDigitState());
		writeOperationOnDisplay();
	}
	
	public void initSecondOperator(int digit) {
		
		getOperationContainer().setSecondOperator(getStringValue(digit));
		setCurrentState(getSecondDigitState());
		writeOperationOnDisplay();
	}
	
	public void initOperation(Operation operation) {
		
		getOperationContainer().setSecondOperator(null);
		getOperationContainer().setOperation(operation);
		setCurrentState(getOperatorState());
		writeOperationOnDisplay();
	}
	
	public void addDigit(String digit) {

		getCurrentState().addDigit(digit);
	}

	public void addDigit(int digit) {

		this.addDigit(getStringValue(digit));
	}

	public void addOperator(String keyValue) {
		
		getCurrentState().addOperator(keyValue);
	}

	public void removeLast() {

		getCurrentState().removeLast();
	}
	
	public void setResult(int result) {
		
		getOperationContainer().setResult(getStringValue(result));
	}

	public void executeOperation(Action<?> action) {
		
		if (action != null) {
			service.execute(action, new AsyncCallback<Result>() {

				public void onFailure(Throwable caught) {

					Window.alert("oops... algo salio mal :(");
				}

				public void onSuccess(Result result) {
					
					getCurrentState().setResult(result);
				}
			});
		}
		
	}
	

	public void writeOperationOnDisplay() {
		view.setOperationText(getOperationContainer().toString());
	}
	
	private String getStringValue(int number) {

		return String.valueOf(number);
	}

}
